package com.scs.application.modules.wm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.query.QueryContext;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.DateUtils;
import com.scs.application.core.utils.StringUtils;
import com.scs.application.core.utils.UserUtils;
import com.scs.application.core.utils.UtilNum;
import com.scs.application.modules.base.entity.Matr;
import com.scs.application.modules.base.entity.MatrUnit;
import com.scs.application.modules.base.mapper.MatrMapper;
import com.scs.application.modules.base.mapper.MatrUnitMapper;
import com.scs.application.modules.dept.entity.ApplyAuto;
import com.scs.application.modules.dept.mapper.ApplyAutoMapper;
import com.scs.application.modules.purchase.enums.PurchaseType;
import com.scs.application.modules.wm.dto.DistDTO;
import com.scs.application.modules.wm.dto.StockGroupWarehouseMatrDTO;
import com.scs.application.modules.wm.entity.*;
import com.scs.application.modules.wm.mapper.DistItemMapper;
import com.scs.application.modules.wm.mapper.DistMapper;
import com.scs.application.modules.wm.service.DistItemService;
import com.scs.application.modules.wm.service.PickItemService;
import com.scs.application.modules.wm.service.StockLockService;
import com.scs.application.modules.wm.service.StockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 配送单明细 服务实现类
 * </p>
 */
@Service
public class DistItemServiceImpl extends BaseServiceImpl<DistItemMapper, DistItem> implements DistItemService {

    @Autowired
    private DistMapper distMapper;

    @Autowired
    private DistItemMapper distItemMapper;

    @Autowired
    private StockService stockService;

    @Autowired
    private StockLockService stockLockService;

    @Autowired
    private ApplyAutoMapper applyAutoMapper;

    @Autowired
    private PickItemService pickItemService;

    @Autowired
    private MatrUnitMapper matrUnitMapper;
    @Autowired
    private MatrMapper matrMapper;

    @Override
    public boolean saveOrUpdate(DistItem entity) {

        // 在一张配送单内不允许配送同一个耗材
        List<DistItem> items = this.list(Wrappers.<DistItem>query().eq("dist_id", entity.getDistId()));

        long count = 0;
        if (entity.isNewRecord()) {
            count = items.stream().filter(item -> item.getMatrId().equalsIgnoreCase(entity.getMatrId())).count();
        } else {
            count = items.stream().filter(item ->
                    item.getMatrId().equalsIgnoreCase(entity.getMatrId()) && !item.getId().equalsIgnoreCase(entity.getId())
            ).count();
        }
        if (count > 0) {
            throw new BusinessException("配送单中耗材不允许重复");
        }

        if (StringUtils.isNotBlank(entity.getId()) && StringUtils.isNotBlank(entity.getBillPackageUnit())) {
            Dist dist = distMapper.selectById(entity.getDistId());
            QueryWrapper queryWrapper = Wrappers.<Stock>query().eq("matr_id", entity.getMatrId()).in("warehouse_id",dist.getWarehouseId());
            List<StockGroupWarehouseMatrDTO> stockGroupWarehouseMatrDTOS= stockService.getListGroupByMatr(queryWrapper);
            if (stockGroupWarehouseMatrDTOS == null || stockGroupWarehouseMatrDTOS.size() < 1) {
                throw new BusinessException("该耗材已无库存，不允许开单");
            }
            List<StockGroupWarehouseMatrDTO> stockGroupWarehouseMatrDTOSDind = stockGroupWarehouseMatrDTOS.stream().filter(ob -> ob.getPackageUnit().equals(entity.getBillPackageUnit())).collect(Collectors.toList());

            if (stockGroupWarehouseMatrDTOS == null || stockGroupWarehouseMatrDTOS.size() < 1) {
                throw new BusinessException("该耗材该开单单位没有可用库存，请开单其他单位");
            }

            double PackageQtyUseSum = UtilNum.getDouble(stockGroupWarehouseMatrDTOSDind.stream().mapToDouble(ob -> ob.getPackageQtyUse()).sum());

            if (entity.getBillPackageQty()  > PackageQtyUseSum)
                throw new BusinessException("该耗材该单位开单数量[%s]已超过可用库存[%s]，请重新修改开单单位或者数量",entity.getBillPackageQty(),PackageQtyUseSum);
        }


        boolean success = super.saveOrUpdate(entity);

        String distId = entity.getDistId();
        updateDistAmount(distId);
        return success;
    }



    @Override
    public boolean removeCascadeByIds(Collection<? extends Serializable> idList) {
        // 查询出明细涉及到的所有配送单
        List<String> distIds = this.listObjs(Wrappers.<DistItem>query()
                        .select("dist_id" ).in("id" , idList).groupBy("dist_id"),
                v -> v.toString());


        for (String distId : distIds) {
            updateDistAmount(distId);
        }

        List<DistItem> distItems = distItemMapper.selectList(Wrappers.<DistItem>query().in("id", idList));
        for (DistItem distItem : distItems) {
            //修改配送需求池相关数据
            if (StringUtils.isNotBlank(distItem.getApplyItemId())){
                Double sumPickQty = this.getObj(Wrappers.<DistItem>query().select("ifnull(sum(picked_sku_qty),0.0)").eq("apply_item_id", distItem.getApplyItemId()), v -> {
                    if (v == null) {
                        return 0.0;
                    }
                    return Double.valueOf(v.toString());
                });
                applyAutoMapper.update(null, Wrappers.<ApplyAuto>update()
                        .set("picked_sku_qty", sumPickQty)
                        .set("ref_id",null)
                        .eq("ref_apply_item_id", distItem.getApplyItemId())
                        .eq("flag_transfer",0).eq("ref_type","dept_apply"));
            }
        }

        return super.removeCascadeByIds(idList);
    }

    private void updateDistAmount(String distId) {
        DistDTO distDTO = distMapper.getDistAmountAndPick(distId);
        Double demandsSum = distMapper.getDistDemand(distId);
        String pickAndDemand = UtilNum.getString(distDTO.getPickQty()) + "-/-" + UtilNum.getString(demandsSum);
        distMapper.calculateDistInfo(distId,pickAndDemand,distDTO.getAmount(), null);
    }





    @Transactional(rollbackFor = Exception.class)
    @Override
    public void cancelPick(String distId) {
        // 配送单数据还原
        Dist dist = distMapper.selectById(distId);
        if (dist == null){
            throw new BusinessException("数据异常，未找到配送单");
        }
        Integer count = pickItemService.count(Wrappers.<PickItem>query().eq("dist_id", distId));

        distMapper.update(dist, Wrappers.<Dist>update().set("picker", null).set("flow_status","picking")
                .set("pick_date", null).set("amount", 0.0).eq("id", distId));
        if (count == null || count == 0) {
            return;
        }
        /*Dist d = new Dist();
        d.setAmount(0.0).setPicker("").setBusDate(null).setId(distId);*/

        // 库存解锁
        List<PickItem> pickItems = pickItemService.list(Wrappers.<PickItem>query().eq("dist_id", distId));
        List<String> stockIds = pickItems.stream().map(o -> o.getStockId()).collect(Collectors.toList());
        List<Stock> stockList = stockService.list(Wrappers.<Stock>query().in("id", stockIds));
        for (Stock stock : stockList) {
            // 解锁库存
            stockLockService.unlock(stock.getId());
        }
        // 删除已拣货明细
        pickItemService.removeByIds(pickItems.stream().map(o -> o.getId()).collect(Collectors.toList()));
        // auto数据还原
        updateApplyAuto(distId);
        // 更新已拣货数量和金额
        distMapper.updatePickAmountQty(distId);

        //手工单据 删除非请领需求并且拣货数量是0的
        if (GlobalConsts.DistTransferSourceType.MANUAL.equals(dist.getSourceType())) {
            distItemMapper.delete(Wrappers.<DistItem>query().eq("dist_id", distId).isNull("apply_id").eq("picked_sku_qty",0));
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void endPick(String distId) {
        Integer count = pickItemService.count(Wrappers.<PickItem>query().eq("dist_id", distId));
        if (count == null || count == 0) {
            throw new BusinessException("请先完成所有配送明细拣货操作");
        }
        // 修改配送单状态
        Dist d = new Dist();
        d.setStatusPick(2).setFlowStatus("picked").setFlowModifier(UserUtils.currentUser().getName())
                .setFlowModified(LocalDateTime.now()).setId(distId);
        d.setPicker(UserUtils.currentUser().getName()).setPickDate(DateUtils.localDateTime2Date(LocalDateTime.now()));
        distMapper.updateById(d);
    }

    @Override
    public Double getpackageRate(String applyItemId) {
        return distItemMapper.getpackageRate(applyItemId);
    }

    @Override
    public List<DistItemPda> findDistItemPda(QueryContext context) {
        return this.baseMapper.findDistItemPda(context.getWrapper());
    }



    private void updateApplyAuto(String distId) {
        List<ApplyAuto> applyAutos = applyAutoMapper.selectList(new QueryWrapper<ApplyAuto>()
                .eq("ref_id", distId)
                .eq("flag_transfer", '0').eq("ref_type","dept_apply"));
        for (ApplyAuto applyAuto : applyAutos) {
            double count = pickItemService.count(new QueryWrapper<PickItem>()
                    .eq("dist_id", applyAuto.getRefId())
                    .eq("matr_id", applyAuto.getMatrId()));
            applyAuto.setPickedSkuQty(count);
            applyAutoMapper.updateById(applyAuto);
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addDtlBatch(List<DistItem> entityList) {
        List<String> matrIdList = entityList.stream().map(DistItem::getMatrId).collect(Collectors.toList());
        //所选耗材所有单位
        Map<String,List<MatrUnit>> matrUnitMap = matrUnitMapper
                .selectList(Wrappers.<MatrUnit>query().in("matr_id", matrIdList).eq("flag_apply", 1).orderByDesc("rate"))
                .stream().collect(Collectors.groupingBy(MatrUnit::getMatrId)); ;
        if (matrUnitMap == null || matrUnitMap.size()< 1)throw new BusinessException("所操作的耗材都没有可用请领单位，请重新选择");

        Map<String,Matr> matrMap =  matrMapper.selectList(Wrappers.<Matr>query().in("id", matrIdList)).stream().collect(Collectors.toMap(Matr::getId, matr -> matr));
        if (matrMap == null || matrMap.size()< 1)throw new BusinessException("所操作的耗材已被删除，请重新选择");

        Map<String,DistItem> distItemDbMap  = this.list(Wrappers.<DistItem>query().eq("dist_id",entityList.get(0).getDistId())).stream().collect(Collectors.toMap(DistItem::getId, distItem -> distItem));

        String distType = "";
        Matr matr;
        List<MatrUnit> matrUnitList;
        MatrUnit matrUnit;
        for(int i=0; i< entityList.size() ;i++) {
            matr = matrMap.get(entityList.get(i).getMatrId());
            matrUnitList = matrUnitMap.get(entityList.get(i).getMatrId());
            if (matr == null )throw new BusinessException("耗材【%s】已被删除，请重新选择", entityList.get(i).getMatrName());
            if (distItemDbMap != null && distItemDbMap.containsKey(matr.getId()) )throw new BusinessException("耗材【%s】已添加过，不可重复添加", entityList.get(i).getMatrName());
            if (matrUnitList == null || matrUnitList.size() < 1 )throw new BusinessException("耗材【%s】没有可用单位，请重新选择或者请联系运营人员进行维护", entityList.get(i).getMatrName());
            matrUnit = matrUnitList.get(0);
            //耗材属性
            entityList.get(i).setMatrId(matr.getId()).setMatrName(matr.getName()).setMatrSpec(matr.getSpec())
                    .setSkuPrice(matr.getSkuPrice()).setSkuUnit(matr.getSkuUnit());

            //包装属性
            entityList.get(i).setPackageUnit(matrUnit.getUnit()).setPackageRate(matrUnit.getRate()).setPackageQty(1d);
            //单品数量
            entityList.get(i).setSkuQty(matrUnit.getRate()).setAmount(matrUnit.getPrice()).setPickedSkuQty(0d);

            //开单属性
            entityList.get(i).setBillPackageUnit(matrUnit.getUnit()).setBillPackageRate(matrUnit.getRate()).setBillPackageQty(1d);

            // 更新配送单耗材类型
            if (PurchaseType.REAGENT.getKey().equals(matr.getBaseType())) {
                distType = PurchaseType.REAGENT.getKey();
            }
        }
        this.saveBatch(entityList);

        if (StringUtils.isNotEmpty(distType)) {
            distMapper.updateById((Dist) new Dist().setDistType(distType).setId(entityList.get(0).getDistId()));
        }
    }
}
